home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / xmodifier.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-29  |  12.1 KB  |  299 lines

  1. /* Grok X modifier mappings for shortcuts.
  2.    
  3.    Most of this code was taken from src/event-Xt.c in XEmacs 20.3-b17.
  4.    The copyright(s) from the original XEmacs code are included below.
  5.  
  6.    Perpetrator: Sudish Joseph <sj@eng.mindspring.net>, Sept. 1997. */
  7.  
  8. /* The event_stream interface for X11 with Xt, and/or tty frames.
  9.    Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
  10.    Copyright (C) 1995 Sun Microsystems, Inc.
  11.    Copyright (C) 1996 Ben Wing.
  12.  
  13. This file is part of XEmacs.
  14.  
  15. XEmacs is free software; you can redistribute it and/or modify it
  16. under the terms of the GNU General Public License as published by the
  17. Free Software Foundation; either version 2, or (at your option) any
  18. later version.
  19.  
  20. XEmacs is distributed in the hope that it will be useful, but WITHOUT
  21. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  22. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  23. for more details.
  24.  
  25. You should have received a copy of the GNU General Public License
  26. along with XEmacs; see the file COPYING.  If not, write to
  27. the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  28. Boston, MA 02111-1307, USA.  */
  29.  
  30. #include "wconfig.h"
  31.  
  32. #include <string.h>
  33. #include <X11/Xlib.h>
  34. #include <X11/keysym.h>
  35.  
  36. #include "WUtil.h"
  37.  
  38.  
  39. extern Display *dpy;
  40.  
  41. /************************************************************************/
  42. /*                            keymap handling                           */
  43. /************************************************************************/
  44.  
  45. /* X bogusly doesn't define the interpretations of any bits besides
  46.    ModControl, ModShift, and ModLock; so the Interclient Communication
  47.    Conventions Manual says that we have to bend over backwards to figure
  48.    out what the other modifier bits mean.  According to ICCCM:
  49.  
  50.    - Any keycode which is assigned ModControl is a "control" key.
  51.  
  52.    - Any modifier bit which is assigned to a keycode which generates Meta_L
  53.      or Meta_R is the modifier bit meaning "meta".  Likewise for Super, Hyper,
  54.      etc.
  55.  
  56.    - Any keypress event which contains ModControl in its state should be
  57.      interpreted as a "control" character.
  58.  
  59.    - Any keypress event which contains a modifier bit in its state which is
  60.      generated by a keycode whose corresponding keysym is Meta_L or Meta_R
  61.      should be interpreted as a "meta" character.  Likewise for Super, Hyper,
  62.      etc.
  63.  
  64.    - It is illegal for a keysym to be associated with more than one modifier
  65.      bit.
  66.  
  67.    This means that the only thing that emacs can reasonably interpret as a
  68.    "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates
  69.    one of the modifier bits Mod1-Mod5.
  70.  
  71.    Unfortunately, many keyboards don't have Meta keys in their default
  72.    configuration.  So, if there are no Meta keys, but there are "Alt" keys,
  73.    emacs will interpret Alt as Meta.  If there are both Meta and Alt keys,
  74.    then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to
  75.    mean "Symbol," but that just confused the hell out of way too many people).
  76.  
  77.    This works with the default configurations of the 19 keyboard-types I've
  78.    checked.
  79.  
  80.    Emacs detects keyboard configurations which violate the above rules, and
  81.    prints an error message on the standard-error-output.  (Perhaps it should
  82.    use a pop-up-window instead.)
  83.  */
  84.  
  85. static int MetaMask, HyperMask, SuperMask, AltMask, ModeMask;
  86.  
  87. static const char *
  88. index_to_name (int indice)
  89. {
  90.   switch (indice)
  91.     {
  92.     case ShiftMapIndex:   return "ModShift";
  93.     case LockMapIndex:    return "ModLock";   
  94.     case ControlMapIndex: return "ModControl";
  95.     case Mod1MapIndex:    return "Mod1";
  96.     case Mod2MapIndex:    return "Mod2";
  97.     case Mod3MapIndex:    return "Mod3";
  98.     case Mod4MapIndex:    return "Mod4";
  99.     case Mod5MapIndex:    return "Mod5";
  100.     default:              return "???";
  101.     }
  102. }
  103.  
  104. static void
  105. x_reset_modifier_mapping (Display *display)
  106. {
  107.   int modifier_index, modifier_key, column, mkpm;
  108.   int warned_about_overlapping_modifiers = 0;
  109.   int warned_about_predefined_modifiers  = 0;
  110.   int warned_about_duplicate_modifiers   = 0;
  111.   int meta_bit  = 0;
  112.   int hyper_bit = 0;
  113.   int super_bit = 0;
  114.   int alt_bit   = 0;
  115.   int mode_bit  = 0;
  116.   XModifierKeymap *x_modifier_keymap = XGetModifierMapping (display);
  117.  
  118. #define modwarn(name,old,other)                            \
  119.   wwarning ("%s (0x%x) generates %s, which is generated by %s.\n\n",        \
  120.           name, code, index_to_name (old), other),            \
  121.   warned_about_overlapping_modifiers = 1
  122.  
  123. #define modbarf(name,other)                            \
  124.   wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n",            \
  125.           name, code, other),                        \
  126.   warned_about_predefined_modifiers = 1
  127.  
  128. #define check_modifier(name,mask)                        \
  129.   if ((1<<modifier_index) != mask)                        \
  130.     wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n",          \
  131.             name, code, index_to_name (modifier_index)),        \
  132.     warned_about_predefined_modifiers = 1
  133.  
  134. #define store_modifier(name,old)                       \
  135.   if (old && old != modifier_index)                       \
  136.     wwarning ("%s (0x%x) generates both %s and %s, which is nonsensical.\n\n",\
  137.             name, code, index_to_name (old),               \
  138.             index_to_name (modifier_index)),               \
  139.     warned_about_duplicate_modifiers = 1;                   \
  140.   if (modifier_index == ShiftMapIndex) modbarf (name,"ModShift");       \
  141.   else if (modifier_index == LockMapIndex) modbarf (name,"ModLock");       \
  142.   else if (modifier_index == ControlMapIndex) modbarf (name,"ModControl"); \
  143.   else if (sym == XK_Mode_switch)                       \
  144.     mode_bit = modifier_index; /* Mode_switch is special, see below... */  \
  145.   else if (modifier_index == meta_bit && old != meta_bit)           \
  146.     modwarn (name, meta_bit, "Meta");                       \
  147.   else if (modifier_index == super_bit && old != super_bit)           \
  148.     modwarn (name, super_bit, "Super");                       \
  149.   else if (modifier_index == hyper_bit && old != hyper_bit)           \
  150.     modwarn (name, hyper_bit, "Hyper");                       \
  151.   else if (modifier_index == alt_bit && old != alt_bit)               \
  152.     modwarn (name, alt_bit, "Alt");                       \
  153.   else                                       \
  154.     old = modifier_index;
  155.  
  156.   mkpm = x_modifier_keymap->max_keypermod;
  157.   for (modifier_index = 0; modifier_index < 8; modifier_index++)
  158.     for (modifier_key = 0; modifier_key < mkpm; modifier_key++) {
  159.       KeySym last_sym = 0;
  160.       for (column = 0; column < 4; column += 2) {
  161.     KeyCode code = x_modifier_keymap->modifiermap[modifier_index * mkpm
  162.                               + modifier_key];
  163.     KeySym sym = (code ? XKeycodeToKeysym (display, code, column) : 0);
  164.     if (sym == last_sym) continue;
  165.     last_sym = sym;
  166.     switch (sym) {
  167.     case XK_Mode_switch:store_modifier ("Mode_switch", mode_bit); break;
  168.     case XK_Meta_L:     store_modifier ("Meta_L", meta_bit); break;
  169.     case XK_Meta_R:     store_modifier ("Meta_R", meta_bit); break;
  170.     case XK_Super_L:    store_modifier ("Super_L", super_bit); break;
  171.     case XK_Super_R:    store_modifier ("Super_R", super_bit); break;
  172.     case XK_Hyper_L:    store_modifier ("Hyper_L", hyper_bit); break;
  173.     case XK_Hyper_R:    store_modifier ("Hyper_R", hyper_bit); break;
  174.     case XK_Alt_L:      store_modifier ("Alt_L", alt_bit); break;
  175.     case XK_Alt_R:      store_modifier ("Alt_R", alt_bit); break;
  176.     case XK_Control_L:  check_modifier ("Control_L", ControlMask); break;
  177.     case XK_Control_R:  check_modifier ("Control_R", ControlMask); break;
  178.     case XK_Shift_L:    check_modifier ("Shift_L", ShiftMask); break;
  179.     case XK_Shift_R:    check_modifier ("Shift_R", ShiftMask); break;
  180.     case XK_Shift_Lock: check_modifier ("Shift_Lock", LockMask); break;
  181.     case XK_Caps_Lock:  check_modifier ("Caps_Lock", LockMask); break;
  182.  
  183.     /* It probably doesn't make any sense for a modifier bit to be
  184.        assigned to a key that is not one of the above, but OpenWindows
  185.        assigns modifier bits to a couple of random function keys for
  186.        no reason that I can discern, so printing a warning here would
  187.        be annoying. */
  188.     }
  189.       }
  190.     }
  191. #undef store_modifier
  192. #undef check_modifier
  193. #undef modwarn
  194. #undef modbarf
  195.  
  196.   /* If there was no Meta key, then try using the Alt key instead.
  197.      If there is both a Meta key and an Alt key, then the Alt key
  198.      is not disturbed and remains an Alt key. */
  199.   if (! meta_bit && alt_bit)
  200.     meta_bit = alt_bit, alt_bit = 0;
  201.  
  202.   /* mode_bit overrides everything, since it's processed down inside of
  203.      XLookupString() instead of by us.  If Meta and Mode_switch both
  204.      generate the same modifier bit (which is an error), then we don't
  205.      interpret that bit as Meta, because we can't make XLookupString()
  206.      not interpret it as Mode_switch; and interpreting it as both would
  207.      be totally wrong. */
  208.   if (mode_bit)
  209.     {
  210.       const char *warn = 0;
  211.       if      (mode_bit == meta_bit)  warn = "Meta",  meta_bit  = 0;
  212.       else if (mode_bit == hyper_bit) warn = "Hyper", hyper_bit = 0;
  213.       else if (mode_bit == super_bit) warn = "Super", super_bit = 0;
  214.       else if (mode_bit == alt_bit)   warn = "Alt",   alt_bit   = 0;
  215.       if (warn)
  216.     {
  217.       wwarning
  218.         ("%s is being used for both Mode_switch and %s.\n\n",
  219.          index_to_name (mode_bit), warn),
  220.         warned_about_overlapping_modifiers = 1;
  221.     }
  222.     }
  223.  
  224.   MetaMask   = (meta_bit   ? (1 << meta_bit)  : 0);
  225.   HyperMask  = (hyper_bit  ? (1 << hyper_bit) : 0);
  226.   SuperMask  = (super_bit  ? (1 << super_bit) : 0);
  227.   AltMask    = (alt_bit    ? (1 << alt_bit)   : 0);
  228.   ModeMask   = (mode_bit   ? (1 << mode_bit)  : 0); /* unused */
  229.  
  230. #if 0
  231.   if (warned_about_overlapping_modifiers)
  232.     wwarning ("\n"
  233. "    Two distinct modifier keys (such as Meta and Hyper) cannot generate\n"
  234. "    the same modifier bit, because Emacs won't be able to tell which\n"
  235. "    modifier was actually held down when some other key is pressed.  It\n"
  236. "    won't be able to tell Meta-x and Hyper-x apart, for example.  Change\n"
  237. "    one of these keys to use some other modifier bit.  If you intend for\n"
  238. "    these keys to have the same behavior, then change them to have the\n"
  239. "    same keysym as well as the same modifier bit.\n");
  240.  
  241.   if (warned_about_predefined_modifiers)
  242.     wwarning ("\n"
  243. "    The semantics of the modifier bits ModShift, ModLock, and ModControl\n"
  244. "    are predefined.  It does not make sense to assign ModControl to any\n"
  245. "    keysym other than Control_L or Control_R, or to assign any modifier\n"
  246. "    bits to the \"control\" keysyms other than ModControl.  You can't\n"
  247. "    turn a \"control\" key into a \"meta\" key (or vice versa) by simply\n"
  248. "    assigning the key a different modifier bit.  You must also make that\n"
  249. "    key generate an appropriate keysym (Control_L, Meta_L, etc).\n");
  250.  
  251.   /* No need to say anything more for warned_about_duplicate_modifiers. */
  252.  
  253.   if (warned_about_overlapping_modifiers || warned_about_predefined_modifiers)
  254.     wwarning ("\n"
  255. "    The meanings of the modifier bits Mod1 through Mod5 are determined\n"
  256. "    by the keysyms used to control those bits.  Mod1 does NOT always\n"
  257. "    mean Meta, although some non-ICCCM-compliant programs assume that.\n");
  258. #endif
  259.     XFreeModifiermap(x_modifier_keymap);
  260. }
  261.  
  262.  
  263. int
  264. wXModifierFromKey(char *key)
  265. {
  266.     if (strcasecmp(key, "SHIFT")==0 && ShiftMask!=0)
  267.       return ShiftMask;
  268.     else if (strcasecmp(key, "CONTROL")==0 && ControlMask!=0)
  269.       return ControlMask;
  270.     else if (strcasecmp(key, "ALT")==0 && AltMask!=0)
  271.       return AltMask;
  272.     else if (strcasecmp(key, "META")==0 && MetaMask!=0)
  273.       return MetaMask;
  274.     else if (strcasecmp(key, "SUPER")==0 && SuperMask!=0)
  275.       return SuperMask;
  276.     else if (strcasecmp(key, "HYPER")==0 && HyperMask!=0)
  277.       return HyperMask;
  278.     else if (strcasecmp(key, "MOD1")==0 && Mod1Mask!=0)
  279.       return Mod1Mask;
  280.     else if (strcasecmp(key, "MOD2")==0 && Mod2Mask!=0)
  281.       return Mod2Mask;
  282.     else if (strcasecmp(key, "MOD3")==0 && Mod3Mask!=0)
  283.       return Mod3Mask;
  284.     else if (strcasecmp(key, "MOD4")==0 && Mod4Mask!=0)
  285.       return Mod4Mask;
  286.     else if (strcasecmp(key, "MOD5")==0 && Mod5Mask!=0)
  287.       return Mod5Mask;
  288.     else
  289.       return -1;
  290. }
  291.  
  292. /* Wrapper so that we may fit the WM naming conventions, yet leave the 
  293.    original XEmacs function name in place. */
  294. void
  295. wXModifierInitialize(void)
  296. {
  297.     x_reset_modifier_mapping(dpy);
  298. }
  299.